/*------------------------------------------------------------------------------
 * Copyright 2012 NCR Corporation
 *------------------------------------------------------------------------------
 * All revision information is updated automatically from source code control
 * change records - please do not manually edit.
 *------------------------------------------------------------------------------
 *
 * $LastChangedRevision:: 2123                                     $
 * $LastChangedBy:: rb250096                                       $
 * $LastChangedDate:: 2012-04-18 00:43:25 -0400 (Wed, 18 Apr 2012) $
 */

package com.ncr.nep.dashboardcore.rest.client;

import java.util.Arrays;

import com.google.gwt.http.client.RequestCallback;
import com.ncr.nep.dashboardcore.utils.client.URLUtil;

/**
 * Base class used to create objects that represent RESTful endpoints and
 * provides convenience methods for invoking HTTP methods on a URL.
 *
 * <p>
 *     In addition to providing convenient methods for invoking HTTP methods,
 *     this class also integrates with the {@link JSONCallback} type for
 *     automatically converting JSON returned from HTTP requests to domain
 *     Object instances via <code>AutoBeans</code>.
 * </p>
 *
 * @author rb250096
 * @version $Revision: 2123 $
 */
public abstract class RESTService {

    //--------------------------------------------------------------------------
    //
    //  Fields
    //
    //--------------------------------------------------------------------------

    /**
     * Base URL of the REST endpoint.  This can be either a relative URL or a
     * full URL with protocol specified.
     */
    protected String baseURL;

    //--------------------------------------------------------------------------
    //
    //  Constructors
    //
    //--------------------------------------------------------------------------

    /**
     * Constructor
     */
    public RESTService() {}

    /**
     * Constructor
     *
     * @param baseURL Base URL of the REST endpoint.
     */
    public RESTService(String baseURL) {
        this.setBaseURL(baseURL);
    }

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------

    /**
     * Gets the base URL of the REST Endpoint. This can be either a relative URL
     * or a full URL with protocol specified.
     *
     * @return The base URL.
     */
    public String getBaseURL() {
        return baseURL;
    }

    /**
     * Sets the base URL of the REST Endpoint. This can be either a relative URL
     * or a full URL with protocol specified.
     *
     * @param baseURL The base URL.  This can either be a fully-qualified
     *                URL including protocol, or a URL relative to the web
     *                host.
     */
    public void setBaseURL(String baseURL) {
        this.baseURL = baseURL;
    }

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

    /**
     * Sends the specified request via <code>GET</code>.
     *
     * @param request The request to send.
     * @param callback Callback to invoke when request is complete.
     */
    protected void get(HTTPRequest request, RequestCallback callback) {
        get(null, request, callback);
    }
    
    /**
     * Sends the specified request via <code>GET</code>.
     *
     * @param subpath Subpath, if any, to append to {@link #baseURL}.
     * @param request The request to send.
     * @param callback Callback to invoke when request is complete.
     */
    protected void get(String subpath, 
                       HTTPRequest request, 
                       RequestCallback callback) {
        request.url(this.generateURL(subpath)).get(callback);
    }

    /**
     * Sends the specified request via <code>POST</code>.
     *
     * @param request The request to send.
     * @param callback Callback to invoke when request is complete.
     */
    protected void post(HTTPRequest request, RequestCallback callback) {
        this.post(null, request, callback);
    }
    
    /**
     * Sends the specified request via <code>POST</code>.
     *
     * @param subpath Subpath, if any, to append to {@link #baseURL}.
     * @param request The request to send.
     * @param callback Callback to invoke when request is complete.
     */
    protected void post(String subpath, 
                        HTTPRequest request, 
                        RequestCallback callback) {
        request.url(this.generateURL(subpath)).post(callback);        
    }

    /**
     * Sends the specified request via <code>PUT</code>.
     *
     * @param request The request to send.
     * @param callback Callback to invoke when request is complete.
     */
    protected void put(HTTPRequest request, RequestCallback callback) {
        this.put(null, request, callback);
    }
    
    /**
     * Sends the specified request via <code>PUT</code>.
     *
     * @param subpath Subpath, if any, to append to {@link #baseURL}.
     * @param request The request to send.
     * @param callback Callback to invoke when request is complete.
     */
    protected void put(String subpath, 
                       HTTPRequest request, 
                       RequestCallback callback) {
        request.url(this.generateURL(subpath)).put(callback);
    }

    /**
     * Sends the specified request via <code>DELETE</code>.
     *
     * @param request The request to send.
     * @param callback Callback to invoke when request is complete.
     */
    protected void delete(HTTPRequest request, RequestCallback callback) {
        this.delete(null, request, callback);
    }

    /**
     * Sends the specified request via <code>DELETE</code>.
     *
     * @param subpath Subpath, if any, to append to {@link #baseURL}.
     * @param request The request to send.
     * @param callback Callback to invoke when request is complete.
     */
    protected void delete(String subpath, 
                          HTTPRequest request, 
                          RequestCallback callback) {
        request.url(this.generateURL(subpath)).delete(callback);
    }
    
    //----------------------------------
    //  Utility methods
    //----------------------------------

    /**
     * Generates full URL to REST endpoint based on <code>baseURL</code> and
     * the specified fragment.
     *
     * @param subpath Part of URL to append to the <code>baseURL</code>.  If
     *                the subpath contains a protocol specification, the
     *                <code>baseURL</code> will be ignored.
     *
     * @return The full URL to the endpoint.  If the subpath contains a
     * protocol specification, the <code>baseURL</code> will be ignored and the
     * subpath will be returned.
     */
    protected String generateURL(String subpath) {
        if(subpath != null && URLUtil.urlHasProtocol(subpath)) {
            return subpath;
        }

        String s = URLUtil.stripSlashes(subpath);
        if(URLUtil.urlHasProtocol(this.baseURL)) {
            return URLUtil.generateURL(this.baseURL, Arrays.asList(s));
        }
        else {
            return URLUtil.generateApiURL(this.baseURL, s);
        }
    }
}
